import {createVNode, reactive, UnwrapNestedRefs} from "vue";
import {ServiceAction} from "~/icesoft/utils/service/ServiceAction";
import {Pagination, TableState} from "~/icesoft/utils/service/types";
import {message, Modal} from "ant-design-vue";
import {JsonResult} from "~/icesoft/utils/request/types";
import {ExclamationCircleOutlined} from '@ant-design/icons-vue';
import {AxiosRequestConfig} from "axios";

export abstract class BaseCrudApi<T> extends ServiceAction<T> {

    tableState: UnwrapNestedRefs<TableState<T>> = reactive<TableState<T>>({
        loading: false,
        columns: [],
        pagination: {
            current: 1,
            defaultPageSize: 20,
            pageSize: 20,
            total: 0,
            showSizeChanger: true,
            size: "small",
        },
        size: "default",
        title: "",
        dataSource: [],
        filterParams: {},
    });

    // @ts-ignore
    createState: UnwrapNestedRefs<CreateState<T>> = reactive({
        visible: false,
        loading: false,
        title: "创建",
        form: {},
    });
    // @ts-ignore
    editState: UnwrapNestedRefs<EditState<T>> = reactive({
        visible: false,
        loading: false,
        title: "编辑",
        form: {},
    });
    // @ts-ignore
    detailState: UnwrapNestedRefs<DetailState<T>> = reactive({
        visible: false,
        loading: false,
        title: "详情",
        form: {},
    });


    onListPage() {
        this.beforeTable(this.tableState);
        this.tableState.loading = true;
        this.query({
            pageIndex: this.tableState.pagination.current,
            pageSize: this.tableState.pagination.pageSize,
        }, this.tableState.filterParams).then((res) => {
            if (res.ok) {
                this.tableState.dataSource = res.data as any;
                this.tableState.pagination.total = Number(res.page?.totalCount);
            }
        }).catch((reason: any) => {
            console.log(reason);
        }).finally(() => {
            this.tableState.loading = false;
            this.afterTable(this.tableState);
        });
    }

    refreshTable() {
        this.onListPage();
    }

    filterTable(entity: T & object) {
        this.tableState.filterParams = entity;
        this.refreshTable();
    }

    onCreate() {
        // @ts-ignore
        this.createState.form = {};
        this.beforeCreate(this.createState);
        this.createState.visible = true;
        this.afterCreate(this.createState);
    }

    onCloseCreate() {
        // @ts-ignore
        this.createState.form = {};
        this.createState.visible = false;
    }

    onEdit(id?: string) {
        // @ts-ignore
        this.editState.form = {};
        this.beforeEdit(this.editState);
        if (id) {
            this.editState.loading = true;
            this.load(id).then((res) => {
                this.editState.form = res.data as any;
            }).catch((reason: any) => {
                console.log(reason);
            }).finally(() => {
                this.editState.loading = false;
                this.afterEdit(this.editState);
                this.editState.visible = true;
            });
        } else {
            this.afterEdit(this.editState);
        }
    }

    onCloseEdit() {
        this.editState.visible = false;
        // @ts-ignore
        this.editState.form = {};
    }

    onDetail(id: string) {
        // @ts-ignore
        this.detailState.form = {};
        this.beforeDetail(this.detailState);
        if (id) {
            this.detailState.loading = true;
            this.load(id).then((res) => {
                this.detailState.form = res.data as any;
            }).catch((reason: any) => {
                console.log(reason);
            }).finally(() => {
                this.detailState.loading = false;
                this.afterDetail(this.detailState);
                this.detailState.visible = true;
            });
        } else {
            this.afterDetail(this.detailState);
        }
    }

    async submit(form: T & any, refreshTable: boolean = true) {
        this.beforeSubmit();
        return new Promise((resolve, reject) => {
            if (!form.id) {
                this.create(form).then((res: any) => {
                    if (res) {
                        message.success("创建成功");
                        if (refreshTable) {
                            this.refreshTable();
                        }
                        this.afterSubmit(res);
                        resolve(res);
                    } else {
                        this.afterSubmit(res);
                        reject(res);
                    }
                });
            } else {
                this.update(form.id, form).then((res: any) => {
                    if (res) {
                        message.success("修改成功");
                        if (refreshTable) {
                            this.refreshTable();
                        }
                        this.afterSubmit(res);
                        resolve(res);
                    } else {
                        this.afterSubmit(res);
                        reject(res);
                    }
                });
            }
        });
    }

    onCloseDetail() {
        this.detailState.visible = false;
        // @ts-ignore
        this.detailState.form = {};
    }

    async onDelete(id: string, title: string = "警告！", msg: string = "您确定要删除此条数据吗？", options: any = {
        confirmButtonText: "删除",
        cancelButtonText: "取消",
        type: "error",
    }, refreshTable: boolean = true) {
        const _this = this;
        return new Promise((resolve, reject) => {
            Modal.confirm({
                title: title,
                icon: createVNode(ExclamationCircleOutlined),
                content: msg,
                onOk() {
                    _this.beforeDelete();
                    _this.delete(id).then((res: any) => {
                        if (res) {
                            _this.afterDelete();
                            message.success(res.msg);
                            if (refreshTable) {
                                _this.refreshTable();
                            }
                            resolve(res);
                        }
                    });
                },
                onCancel() {
                    console.log('Cancel');
                },
            })
        });
    }

    query(pagination?: Pagination, entity?: any): Promise<JsonResult<T[]>> {
        if (!pagination) {
            pagination = {};
        }
        if (!entity) {
            entity = {};
        }
        let params: any = Object.assign(pagination, entity);
        return this.http.get(this.baseUrl + "/query", {params});
    }

    load(id: string): Promise<JsonResult<T>> {
        return this.http.get(this.baseUrl + `/${id}`);
    }

    create(entity: any): Promise<JsonResult<T>> {
        return this.http.post(this.baseUrl + `/create`, entity);
    }

    update(id: string, entity: any): Promise<JsonResult<T>> {
        return this.http.post(this.baseUrl + `/update/${id}`, entity);
    }

    delete(id: string): Promise<JsonResult<T>> {
        return this.http.get(this.baseUrl + `/delete/${id}`);
    }

    onTableChange(pagination: {
        current: number
        defaultPageSize: number
        pageSize: number
        showSizeChanger: boolean
        size: "default" | "middle" | "small"
        total: number
    }) {
        this.tableState.pagination.current = pagination.current;
        this.tableState.pagination.defaultPageSize = pagination.defaultPageSize;
        this.tableState.pagination.pageSize = pagination.pageSize;
        this.tableState.pagination.showSizeChanger = pagination.showSizeChanger;
        this.tableState.pagination.size = pagination.size;
        this.tableState.pagination.total = pagination.total;
        this.refreshTable()
    }

    get<T = any>(url: string, config?: AxiosRequestConfig, token: boolean = true): Promise<T> {
        return this.http.get(this.baseUrl + url, config, token)
    }

    post<T = any>(url: string, data?: object, config?: AxiosRequestConfig, token: boolean = true): Promise<T> {
        return this.http.post(this.baseUrl + url, data, config, token)
    }

    put<T = any>(url: string, data?: object, config?: AxiosRequestConfig, token: boolean = true): Promise<T> {
        return this.http.put(this.baseUrl + url, data, config, token)
    }

}
